package com.jyh.blog.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jyh.blog.dao.*;
import com.jyh.blog.dto.CommentBackDTO;
import com.jyh.blog.dto.CommentDTO;
import com.jyh.blog.dto.ReplyCountDTO;
import com.jyh.blog.dto.ReplyDTO;
import com.jyh.blog.entity.Comment;
import com.jyh.blog.service.BlogInfoService;
import com.jyh.blog.service.CommentService;
import com.jyh.blog.service.RedisService;
import com.jyh.blog.utils.HTMLUtils;
import com.jyh.blog.utils.PageUtils;
import com.jyh.blog.utils.UserUtils;
import com.jyh.blog.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

import static com.jyh.blog.constant.CommonConst.*;
import static com.jyh.blog.constant.RedisPrefixConst.COMMENT_LIKE_COUNT;
import static com.jyh.blog.constant.RedisPrefixConst.COMMENT_USER_LIKE;
import static com.jyh.blog.enums.CommentTypeEnum.getCommentEnum;
import static com.jyh.blog.enums.CommentTypeEnum.getCommentPath;

/**
 * (Comment)表服务实现类
 *
 * @author jyh
 * @since 2023-02-19 15:58:48
 */
@Service("commentService")
public class CommentServiceImpl extends ServiceImpl<CommentDao, Comment> implements CommentService {
    @Autowired
    private CommentDao commentDao;
    @Autowired
    private RedisService redisService;
    @Autowired
    private BlogInfoService blogInfoService;
    @Autowired
    private UserInfoDao userInfoDao;
    @Autowired
    private ArticleDao articleDao;
    @Autowired
    private TalkDao talkDao;
    @Autowired
    private UserDao userDao;
    @Value("${website.url}")
    private String WEBSITE_URL;
    @Value("${spring.mail.username}")
    private String from;
    @Autowired
    private JavaMailSender mailSender;

    @Override
    public PageResult<CommentDTO> commentList(CommentVO commentVO) {
        //查询评论量
        int count = this.count(new LambdaQueryWrapper<Comment>()
                .eq(Objects.nonNull(commentVO.getTopicId()), Comment::getTopicId, commentVO.getTopicId())
                .eq(Comment::getType, commentVO.getType())
                .eq(Comment::getIsReview, TRUE)
                .isNull(Comment::getParentId)
        );
        if (count == 0) {
            return new PageResult<>();
        }
        //分页查询评论数据（patent_id为null的根评论）
        List<CommentDTO> commentList = commentDao.pageList(PageUtils.getLimitCurrent(), PageUtils.getSize(), commentVO);
        if (CollectionUtils.isEmpty(commentList)) {
            return new PageResult<>();
        }
        //评论id集合
        List<String> commentIdList = commentList.stream()
                .map(CommentDTO::getId)
                .collect(Collectors.toList());
        //根据评论id查询回复数据
        List<ReplyDTO> replyDTOList = commentDao.replyList(commentIdList);
        //redis 中获取点赞数据，key为评论id，value为点赞量
        Map<String, Object> likeCountMap = redisService.hGetAll(COMMENT_LIKE_COUNT);
        //封装回复点赞量
        replyDTOList.forEach(item -> item.setLikeCount((Integer) likeCountMap.get(item.getId())));
        //回复数据根据所属评论id分组
        Map<String, List<ReplyDTO>> replyDTOMap = replyDTOList.stream().collect(Collectors.groupingBy(ReplyDTO::getParentId));
        //根据评论id查询回复量
        Map<String, Integer> replyCountMap = commentDao.replyCountListByCommentId(commentIdList)
                .stream()
                .collect(Collectors.toMap(ReplyCountDTO::getCommentId, ReplyCountDTO::getReplyCount));
        //封装
        commentList.forEach(item -> {
            item.setReplyCount(replyCountMap.get(item.getId()));
            item.setLikeCount((Integer) likeCountMap.get(item.getId()));
            item.setReplyDTOList(replyDTOMap.get(item.getId()));
        });
        return new PageResult<>(commentList, count);
    }

    @Override
    public void saveComments(CommentVO commentVO) {
        //是否需要审核
        WebsiteConfigVO webSiteConfig = blogInfoService.getWebSiteConfig();
        Integer isReview = webSiteConfig.getIsCommentReview();
        //过滤评论内容中的标签
        String commentContent = HTMLUtils.filter(commentVO.getCommentContent());
        //封装评论信息
        Comment comment = Comment.builder()
                .userId(UserUtils.getLoginUser().getUserInfoId())
                .topicId(commentVO.getTopicId())
                .type(commentVO.getType())
                .commentContent(commentContent)
                .parentId(commentVO.getParentId())
                .isReview(isReview == FALSE ? TRUE : FALSE)
                .replyUserId(commentVO.getReplyUserId())
                .build();
        this.save(comment);
        //是否开启自动邮箱通知，通知用户
        if (webSiteConfig.getIsEmailNotice() == TRUE) {
            CompletableFuture.runAsync(() -> notice(comment));
        }
    }

    @Override
    public void commentLike(String commentId) {
        String key=COMMENT_USER_LIKE+UserUtils.getLoginUser().getUserInfoId();
        if(redisService.sIsMember(key,commentId)){
            redisService.sRemove(key,commentId);
            redisService.hDecr(COMMENT_LIKE_COUNT,commentId,1L);
        }else{
            redisService.sAdd(key,commentId);
            redisService.hIncr(COMMENT_LIKE_COUNT,commentId,1L);
        }
    }

    @Override
    public List<ReplyDTO> replyByCommentId(String commentId) {
        List<ReplyDTO> replyDTOList= commentDao.replyByCommentId(PageUtils.getLimitCurrent(),PageUtils.getSize(),commentId);
        //点赞量
        Map<String, Object> commentLikeMap = redisService.hGetAll(COMMENT_LIKE_COUNT);
        replyDTOList.forEach(item->{
            item.setLikeCount((Integer) commentLikeMap.get(item.getId()));
        });
        return replyDTOList;
    }

    @Override
    public PageResult<CommentBackDTO> commentBackList(ConditionVO conditionVO) {
        int count= commentDao.countCommentBack(conditionVO);
        if(count==0){
            return new PageResult<>();
        }
        List<CommentBackDTO> commentBackDTOList= commentDao.commentBackList(PageUtils.getLimitCurrent(),PageUtils.getSize(),conditionVO);
        return new PageResult<>(commentBackDTOList,count);
    }

    @Override
    public void commentReview(ReviewVO reviewVO) {
        //遍历id集合，将每一个id封装对应的comment对象
        List<Comment> commentList = reviewVO.getIdList().stream().map(id -> Comment.builder()
                .id(id)
                .isReview(reviewVO.getIsReview())
                .build()
        ).collect(Collectors.toList());
        this.updateBatchById(commentList);
    }

    //待优化：删除redis中对应的评论点赞
    @Override
    public void deleteCommentByIds(List<String> commentIds) {
        //删除所有父评论id为传参中的id
        this.remove(new LambdaQueryWrapper<Comment>().in(Comment::getParentId,commentIds));
        //删除评论id
        this.removeByIds(commentIds);
    }

    /**
     * 邮箱通知
     *
     * @param comment
     */
    private void notice(Comment comment) {
        //默认博主
        String userId = BLOGGER_ID;
        String topicId = Objects.nonNull(comment.getTopicId()) ? comment.getTopicId() : "";
        if(Objects.nonNull(comment.getReplyUserId())){
            //如果有回复id
            userId=comment.getReplyUserId();
        }else{
            //考虑后续可能多个用户有发布文章的权限
            switch (getCommentEnum(comment.getType())){
                case ARTICLE:
                    userId=articleDao.selectById(topicId).getUserId();
                    break;
                case TALK:
                    userId=talkDao.selectById(topicId).getUserId();
            }
        }
        String email = userInfoDao.selectById(userId).getEmail();
        //邮箱不为空时才能发，扫描登录可能没有绑定邮箱
        if(StringUtils.isNotBlank(email)){
            SimpleMailMessage message=new SimpleMailMessage();
            message.setFrom("江一行的博客<"+from+">");
            //开启邮件提醒
            if(blogInfoService.getWebSiteConfig().getIsEmailNotice()==TRUE){
                message.setSubject("评论提醒");
                message.setTo(email);
                String url= WEBSITE_URL+getCommentPath(comment.getType())+topicId;
                message.setText("请前往"+url+"\n页面查看");
            }else{
                //通知管理员
                message.setSubject("审核提醒");
                String adminEmail = userInfoDao.selectById(BLOGGER_ID).getEmail();
                message.setTo(adminEmail);
                message.setText("您收到了一条新的回复，请前往后台管理页面审核");
            }
            mailSender.send(message);
        }

    }
}

